using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.IO;

namespace Nojin.Deployment
{
    /// <summary>
    /// Objects of this class contains information required for update progress, such as list of files to be
    /// downloaded and install action for each file.
    /// </summary>    
    public class DeploymentManifest
    {
        /// <summary>
        /// Constructs an instance of <seealso cref="DeploymentManifest"/>.
        /// </summary>
        public DeploymentManifest()
        {
            this.downloads = new List<DownloadEntry>();
        }

        #region Properties
        private List<DownloadEntry> downloads;
        /// <summary>
        /// Gets list of downloads.
        /// </summary>        
        public List<DownloadEntry> Downloads
        {
            get
            {
                return downloads;
            }
        }
        #endregion

        #region Methods
        /// <summary>
        /// Loads the manifest from the specified file.
        /// This method is responsible to load files saved by this class's <seealso cref="Save"/> method.
        /// </summary>
        /// <param name="manifestFilePath">Path to the file containing the manifest saved information.</param>
        /// <returns></returns>
        public static DeploymentManifest Load(string manifestFilePath)
        {
            if (manifestFilePath == "")
                throw new ArgumentException("manifestFilePath should be specified.", "manifestFilePath");

            XmlSerializer serializer = new XmlSerializer(typeof(DeploymentManifest));

            using (FileStream fileStream = new FileStream(manifestFilePath, FileMode.Open))
            {
                DeploymentManifest manifest = (DeploymentManifest)serializer.Deserialize(fileStream);
                fileStream.Close();
                return manifest;
            }

        }
        /// <summary>
        /// Save the specified manifest in the specified path.
        /// </summary>
        /// <param name="manifestFilePath">Path to wrtie the result file.</param>
        /// <param name="manifest">The manifest object to save in file.</param>
        public static void Save(string manifestFilePath, DeploymentManifest manifest)
        {
            if (manifestFilePath == "")
                throw new ArgumentException("manifestFilePath should be specified.", "manifestFilePath");
            if (manifest == null)
                throw new ArgumentException("manifest should be specified.", "manifest");

            XmlSerializer serializer = new XmlSerializer(typeof(DeploymentManifest));
            using (FileStream fileStream = new FileStream(manifestFilePath, FileMode.Create))
            {
                serializer.Serialize(fileStream, manifest);
                fileStream.Close();
            }
        }
        #endregion

    }

    /// <summary>
    /// Defines a required download for update.
    /// Each download entry composed by uri, targetPath and installAction.
    /// Uri is Place where the file could be downloaded from.
    /// TargetPath is relative path to save the file in the client.
    /// InstallAction specifies which operation to perform after downloading, simply the file may be copied,
    /// or it could be a zip file, so it may becomes unzipped, or it should be executed.
    /// </summary>
    public class DownloadEntry
    {

        #region Properties
        string uri;
        /// <summary>
        /// Place where the file could be downloaded from.
        /// </summary>
        public string Uri
        {
            get
            {
                return uri;
            }
            set
            {
                uri = value;
            }
        }

        string targetPath;
        /// <summary>
        /// TargetPath is relative path to save the file in the client.
        /// To copy the file inside the application leave it empty.
        /// </summary>
        public string TargetPath
        {
            get
            {
                return targetPath;
            }
            set
            {
                targetPath = value;
            }
        }

        InstallAction installAction;
        /// <summary>
        /// Specifies which operation to perform after downloading, simply the file may be copied,
        /// or it could be a zip file, so it may becomes unzipped, or it should be executed.
        /// </summary>
        public InstallAction InstallAction
        {
            get
            {
                return installAction;
            }
            set
            {
                installAction = value;
            }
        }
        #endregion

        #region Methods
        /// <summary>
        /// Returns a String that represents the current DownloadEntry.
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {                        
            return uri + "(" + installAction + ")";
        }
        #endregion

    }

    /// <summary>
    /// Operations which are appliable to downloaded files.
    /// Update progress copies the files to a tempory location, then applies one of this 
    /// operation to that file in order to install the file.
    /// </summary>
    public enum InstallAction
    {
        /// <summary>
        /// The downloaded file will be copied inside subject application.        
        /// </summary>
        Copy,
        /// <summary>
        /// The downloaded file will be extracted inside subject application.
        /// </summary>
        UnzipCopy,
        /// <summary>
        /// The downloaded file will be executed. You may execute the patch(*.msp).
        /// </summary>
        Run,
        /// <summary>
        /// This option is not implemented.
        /// DONT USE IT.
        /// </summary>
        UnzipRun
    }

}
